home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
SCCVEC.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-12
|
7KB
|
286 lines
; SCC interrupt handler for IBM-PC
include pmacros.h
; variables from C
dseg
extvar sccvecloc,word
extvar sccmaxvec,byte
extvar sccpolltab,word
ifdef LARGEDATA
extvar sccchan,dword
else
extvar sccchan,word
endif
dsegend
; variables from pcint.asm
dseg
extvar sssave,word
extvar spsave,word
extvar intstk,byte
dsegend
extproc doret
; sccvec is the interrupt handler for SCC interrupts using INTACK
pubproc sccvec
cli ; this code is not re-entrant, so make sure it
; is not interrupted. some multi-taskers
; intercept interrupt handlers, so be careful!
push ax ; save ax first.
push ds ; save on user stack
getds
mov ds,ax
mov sssave@,ss ; stash user stack context
mov spsave@,sp
mov ss,ax ; set up interrupt stack
lea sp,intstk@
push bx ; save user regs on interrupt stack
push cx
push dx
push bp
push si
push di
push es
ifndef LARGEDATA
mov es,ax ; small data assumes ES == DS
endif
if TURBO or MSC
cld ; in case "movsb" or "movsw" is used
endif
; Read SCC interrupt vector and check it
sccint: mov dx,sccvecloc@
out dx,al ; Generate INTACK
jmp short d1 ; Delay
d1: jmp short d2
d2: jmp short d3
d3: in al,dx ; Read the vector
cmp al,sccmaxvec@ ; Check for a legal vector
jnc clrret ; It should not be >= the maximum
; If it is, ignore the interrupt
; Extract channel number and status from vector. Determine handler address.
mov bl,al ; Copy vector (need it later for status)
shr bl,1 ; Discard least significant bit
jc clrret ; It should not be a 1
and bx,7ch ; Isolate channel number (and make word)
xor bl,04h ; Toggle A/B channel bit
ifdef LARGEDATA
les si,sccchan@[bx] ; Read address of channel structure
else
shr bl,1 ; Discard another bit
mov si,sccchan@[bx] ; Read address of channel structure
endif
test si,si ; Test for NULL
je clrret ; No channel struct, ignore it
and ax,06h ; Isolate status info from vector
add ax,ax ; Make index in FAR PTR array
mov bx,ax ; It must be in BX
; Call the handler (defined in C), with sccchan struct as a parameter
pushes
push si ; Put channel struct as a parameter
ifdef LARGEDATA
call dword ptr es:[bx+si] ; Call the handler
else
call dword ptr [bx+si] ; Call the handler
endif
pop si ; Get channel struct back
popes
; Reset highest priority interrupt
ifdef LARGEDATA
mov dx,es:16[si] ; Get control register address
else
mov dx,16[si] ; Get control register address
endif
mov al,38h ; "Reset Highest IUS" opcode
out dx,al ; to WR0
jmp short d4 ; settling delay
d4: jmp short d5
d5:
; Determine if more interrupt requests are coming in from the SCCs
jmp sccint ; keep trying until no vector returned
; Clear the ISR bit in the PIC and return from interrupt
clrret: jmp doret@ ; execute code in pcint.asm
pend sccvec
; sccnovec is the interrupt handler for SCC interrupts using polling
pubproc sccnovec
cli ; this code is not re-entrant, so make sure it
; is not interrupted. some multi-taskers
; intercept interrupt handlers, so be careful!
push ax ; save ax first.
push ds ; save on user stack
getds
mov ds,ax
mov sssave@,ss ; stash user stack context
mov spsave@,sp
mov ss,ax ; set up interrupt stack
lea sp,intstk@
push bx ; save user regs on interrupt stack
push cx
push dx
push bp
push si
push di
push es
ifndef LARGEDATA
mov es,ax ; small data assumes ES == DS
endif
if TURBO or MSC
cld ; in case "movsb" or "movsw" is used
endif
; Find the SCC generating the interrupt by polling all attached SCCs
; reading RR3A (the interrupt pending register)
sccintnv:
lea si,sccpolltab@ ; Point to polling table
sccpoll:
mov dx,[si] ; Get chan A CTRL address
inc si
inc si
test dx,dx ; End of table without finding it
je clrret ; Then return from interrupt
mov al,3 ; Select RR3A
out dx,al
jmp short d6 ; Delay
d6: jmp short d7
d7: jmp short d8
d8: in al,dx
test al,al ; Test if a nonzero IP here
jnz sccip ; Yes, handle it
inc si ; No, next A CTRL
inc si
jmp sccpoll
; Read SCC interrupt vector from RR2B, it should always be correct
; Extract channel number and status from vector. Determine handler address.
sccip: mov dx,[si] ; Read B CTRL address
mov al,2 ; Select RR2B
out dx,al
jmp short d9 ; Delay
d9: jmp short d10
d10: jmp short d11
d11: in al,dx ; Read the vector
mov bl,al ; Copy vector (need it later for status)
shr bl,1 ; Discard least significant bit
and bx,7ch ; Isolate channel number (and make word)
xor bl,04h ; Toggle A/B channel bit
ifdef LARGEDATA
les si,sccchan@[bx] ; Read address of channel structure
else
shr bl,1 ; Discard another bit (sccchan=words)
mov si,sccchan@[bx] ; Read address of channel structure
endif
test si,si ; Test for NULL
je clrret ; No channel struct, ignore it
and ax,06h ; Isolate status info from vector
add ax,ax ; Make index in FAR PTR array
mov bx,ax ; It must be in BX
; Call the handler (defined in C), with sccchan struct as a parameter
pushes
push si ; Put channel struct as a parameter
ifdef LARGEDATA
call dword ptr es:[bx+si] ; Call the handler
else
call dword ptr [bx+si] ; Call the handler
endif
pop si ; Remove parameter from stack
popes
; Check for more interrupt pending bits
jmp sccintnv
pend sccnovec
; scctvec is called as the replacement timer tick interrupt handler every 55ms.
; it calls scctim() and then jumps to the original handler.
; when the constant SCC_HWTIMER is defined during compilation of SCC.C,
; we'll install it directly on the timer hardware interrupt, not on the
; timer-tick user-exit (int 1c) because some programs take over that one
; without saving and calling the original handler installed there...
; (also, Phil Karn points out the int 1c is sluggish when DoubleDos is running)
extproc scctim
pubproc scctvec
cli ; this code is not re-entrant, so make sure it
; is not interrupted. some multi-taskers
; intercept interrupt handlers, so be careful!
push ax ; save ax first.
push ds ; save on user stack
getds
mov ds,ax
mov sssave@,ss ; stash user stack context
mov spsave@,sp
mov ss,ax ; set up interrupt stack
lea sp,intstk@
push bx ; save user regs on interrupt stack
push cx ; (only those not saved by C)
push dx
push es
ifndef LARGEDATA
mov es,ax ; small data assumes ES == DS
endif
call scctim@ ; call timer tick routine (in C)
pop es ; restore everything
pop dx
pop cx
pop bx
mov ss,sssave@
mov sp,spsave@ ; restore original stack context
pop ds
pop ax
db 0eah ; opcode for a far jump
pubvar sccotvec,<dw 0,0ffffh> ; original INT handler address
; is stored here by initialization code
pend scctvec
end